package cn.com.yang.socket;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 简单文件服务器
 * TODO
 * @author yangyijin
 * @since 2023年5月14日-下午7:57:15
 */
public class SimpleFileHTTPServer {
	private static final Logger logger = Logger.getLogger("SimpleFileHTTPServer");
	private final byte[] content;
	private final byte[] header;
	private final int port;
	private final String encoding;
	public SimpleFileHTTPServer(String data,String encoding, String mimetype, int port) throws UnsupportedEncodingException {
		this(data.getBytes(encoding),encoding,mimetype,port);
	}
	public SimpleFileHTTPServer(byte[] data, String encoding, String mimetype, int port) {
		this.content = data;
		this.port = port;
		this.encoding = encoding;
		String header = "HTTP/1.0 200 OK\r\n"
				+"Server: OneFile 2.0\r\n"
				+"Content-Length: "+this.content.length+"\r\n"
				+"Content-Type: "+mimetype+"; charset="+encoding+"\r\n\r\n";
		this.header = header.getBytes(Charset.forName("US-ASCII"));
	}
	public void start() {
		ExecutorService pool = Executors.newFixedThreadPool(100);
		try(ServerSocket server = new ServerSocket(this.port)){
			logger.info("Accepting connections on port "+server.getLocalPort());
			logger.info("Data to be send:");
			logger.info(new String(this.content,encoding));
			while(true) {
				try {
					Socket conn = server.accept();
					pool.submit(new HTTPHandler(conn));
				} catch (IOException e) {
					logger.log(Level.WARNING,"exception accpeting connection :",e);
				}catch (RuntimeException e) {
					logger.log(Level.SEVERE,"Unexpected error:",e);
				}
			}
		}catch (IOException e) {
			logger.log(Level.SEVERE,"could not start server:",e);
		}
	}
	
	private class HTTPHandler implements Callable<Void>{
		private final Socket conn;
		HTTPHandler(Socket conn) {
			this.conn = conn;
		}
		@Override
		public Void call() throws Exception {
			try (OutputStream out = new BufferedOutputStream(conn.getOutputStream());
				InputStream ins = new BufferedInputStream(conn.getInputStream())){
				//只读取第一行，这是我们的全部内容
				StringBuilder req = new StringBuilder(80);
				while(true) {
					int c = ins.read();
					if (c=='\r'||c=='\n'||c==-1)break;
					req.append((char)c);
				}
				//如果是HTTP/1.0以后的版本，则发送一个MIME首部
				if(req.toString().indexOf("HTTP/") !=-1) {
					out.write(header);
				}
				out.write(content);
				out.flush();
			} catch (IOException e) {
				logger.log(Level.WARNING,"Error writing to client: ",e);
			}finally {
				conn.close();
			}
			return null;
		}
	}
	
	public static void main(String[] args) {
		//设置监听的端口
		int port;
		try {
			port =Integer.parseInt(args[1]);
			if (port <1 || port>65535) port=80;
		} catch (Exception e) {
			port =80;
		}
		String encoding ="UTF-8";
		if (args.length > 2)encoding=args[2];
		try {
			Path path = Paths.get(args[0]);//java.nio
			byte [] data = Files.readAllBytes(path);//java.nio
			String contentType = URLConnection.getFileNameMap().getContentTypeFor(args[0]);
			SimpleFileHTTPServer server = new SimpleFileHTTPServer(data, encoding, contentType, port);
			server.start();
		}catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("Usage: java SimpleFileHTTPServer filename port encoding");
		}catch (IOException e) {
			logger.severe(e.getMessage());
		}
	}
}
